package com.lenovo.spider.domain;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import lombok.*;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.RequestBody;

import java.io.Serializable;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/**
 * 请求
 *
 * @author <a href="mailto:liuhan3@lenovo.com">HanL(liuhan3)</a>
 * on 2018/3/19 18:06
 */
@Data
@ToString(of = {"url", "downloaderType"})
@Builder
public class Request implements Serializable {
    public static final String GET = "get";
    public static final String POST = "post";

    private String url;
    private String method;
    private Proxy proxy;
    private Map<String, String> headers;
    private Map<String, String> cookies;
    private Map<String, Object> extra;
    private Params params;
    private Boolean checkDuplicate;
    private DownloaderType downloaderType;
    private int priority;

    public String getMethod() {
        return Optional.ofNullable(method).orElse(GET);
    }

    public boolean isCheckDuplicate() {
        return Optional.ofNullable(checkDuplicate).orElse(true);
    }

    public boolean hasParams() {
        if (StrUtil.equalsIgnoreCase(GET, method)) {
            return params != null && params.bodyType == BodyType.QUERY && CollUtil.isNotEmpty(params.body);
        } else {
            return params != null && CollUtil.isNotEmpty(params.body);
        }
    }

    @Getter
    public static class Params {
        private BodyType bodyType;
        private Map<String, Object> body;

        private Params(BodyType bodyType, Map<String, Object> body) {
            this.bodyType = bodyType;
            this.body = body;
        }

        public RequestBody toRequestBody() {
            if (CollUtil.isEmpty(body)) {
                body = MapUtil.newHashMap(1);
            }
            return bodyType.converter().apply(body);
        }
    }

    public enum DownloaderType {
        HTTP,
        WEBDRIVER;
    }


    public enum BodyType {
        QUERY {
            @Override
            public Function<Map<String, Object>, ? extends RequestBody> converter() {
                return null;
            }
        },
        XML {
            @Override
            public Function<Map<String, Object>, ? extends RequestBody> converter() {
                return null;
            }
        },
        FORM {
            @Override
            public Function<Map<String, Object>, FormBody> converter() {
                return params -> {
                    val bodyBuilder = new FormBody.Builder();
                    params.forEach((k, v) -> bodyBuilder.add(k, v.toString()));
                    return bodyBuilder.build();
                };
            }
        },
        JSON {
            @Override
            public Function<Map<String, Object>, ? extends RequestBody> converter() {
                return params -> RequestBody.create(MediaType.parse("application/json;charset=utf8"),
                        com.alibaba.fastjson.JSON.toJSONString(params));
            }
        };

        public Params create(Map<String, Object> data) {
            return new Params(this, data);
        }

        public abstract Function<Map<String, Object>, ? extends RequestBody> converter();
    }

}
